UNIX(7) | Руководство программиста Linux | UNIX(7) |
ИМЯ¶
unix - сокеты для локального межпроцессного взаимодействия
ОБЗОР¶
#include <sys/socket.h>
#include <sys/un.h>
unix_socket = socket(AF_UNIX, type, 0);
error = socketpair(AF_UNIX, type, 0, int *sv);
ОПИСАНИЕ¶
Семейство сокетов AF_UNIX (также известное, как AF_LOCAL) используется для эффективного взаимодействия между процессами на одной машине. Доменные сокеты UNIX могут быть как безымянными, так и иметь имя файла в файловой системе (типизированный сокет). В Linux также поддерживается абстрактное пространство имён, которое не зависит от файловой системы.
Допустимые типы: потоковый сокет SOCK_STREAM и датаграмный сокет SOCK_DGRAM, сохраняющий границы сообщений (в большинстве реализаций UNIX, доменные датаграмные сокеты UNIX всегда надёжны и не меняют порядок датаграмм); и (начиная с Linux 2.6.4) ориентированный на соединение сокет SOCK_SEQPACKET, сохраняющий границы сообщений и доставляющий сообщения в том же порядке, в каком они были отправлены.
Доменные сокеты UNIX поддерживают передачу файловых дескрипторов или информацию (credentials) о процессе другим процессам, используя вспомогательные (ancillary) данные.
Формат адреса¶
Адрес
доменного
сокета UNIX
представляет
собой
следующую
структуру:
#define UNIX_PATH_MAX 108 struct sockaddr_un {
sa_family_t sun_family; /* AF_UNIX */
char sun_path[UNIX_PATH_MAX]; /* имя пути */ };
sun_family всегда содержит AF_UNIX.
В этой структуре различают три типа адресов:
- с именем пути: доменный сокет UNIX может быть привязан к имени пути (с завершающимся null) в файловой системе с помощью bind(2). При возврате адреса сокета с помощью getsockname(2), getpeername(2) и accept(2), его длина равна offsetof(struct sockaddr_un, sun_path) + strlen(sun_path) + 1, а в sun_path содержится имя пути с завершающимся null.
- безымянный: Потоковый сокет, который не привязан к имени пути с помощью bind(2), не имеет имени. Аналогично, два сокета, создаваемые socketpair(2), также не имеют имён. При возврате адреса сокета с помощью getsockname(2), getpeername(2) и accept(2), его длина равна sizeof(sa_family_t), а значение sun_path не используется.
- абстрактный: абстрактный адрес сокета отличается тем, что значением sun_path[0] является байт null ('\0'). Адрес сокета в этом пространстве имён определяется дополнительными байтами в sun_path, количество которых определяется длиной указанной структуры адреса. Байты null в имени не имеют специального значения. Имя не связано с именем пути в файловой системе. При возврате адреса абстрактного сокета с помощью getsockname(2), getpeername(2) и accept(2), возвращаемое значение addrlen больше чем sizeof(sa_family_t) (т.е. больше 2), а имя сокета содержится в первых (addrlen - sizeof(sa_family_t)) байтах sun_path. Пространство имён абстрактных сокетов является непереносимым расширением Linux.
Параметры сокетов¶
В силу исторических причин эти параметры сокетов относятся к типу SOL_SOCKET, даже если они относятся к AF_UNIX. Они могут быть установлены с помощью setsockopt(2) и прочитаны с помощью getsockopt(2); тип SOL_SOCKET указывается в качестве семейства сокета.
- SO_PASSCRED
- Разрешает приём информационных данных (credentials) посылающего процесса во вспомогательном сообщении. Если при включении этого параметра сокет пока ещё не соединён, то в абстрактном пространстве имён будет автоматически создано уникальное имя. Ожидается целочисленный логический флаг.
Свойство автоматической привязки¶
Если в вызов bind(2) передано значение addrlen равное sizeof(sa_family_t), или для сокета, который не привязан к адресу явно, был указан параметр сокета SO_PASSCRED, то сокет автоматически привязывается к абстрактному адресу. Адрес состоит из байта null и 5 байтов символов из набора [0-9a-f]. Таким образом, максимальное количество автоматически привязываемых адресов равно 2^20 (в Linux 2.1.15, когда была добавлена автоматическая привязка, использовалось 8 байт, и, таким образом, ограничение было 2^32 адресов. В Linux 2.3.15 количество байт сократили до 5).
Программный интерфейс сокетов¶
В следующих параграфах описываются специфичные тонкости доменов и неподдерживаемые возможности программного интерфейса сокетов для доменных сокетов UNIX в Linux.
Доменные сокеты UNIX не поддерживают передачу внеполосных данных (флаг MSG_OOB у send(2) и recv(2)).
Флаг MSG_MORE у send(2) не поддерживается доменными сокетами UNIX.
Использование MSG_TRUNC в аргументе flags у recv(2) не поддерживается доменными сокетами UNIX.
Параметр сокета SO_SNDBUF учитывается в доменных сокетах UNIX, а параметр SO_RCVBUF — нет. Для датаграмных сокетов значение SO_SNDBUF считается максимальным размером для исходящих датаграмм. Это ограничение, вычисляемое как удвоенное значение (см. socket(7)) параметра, содержит меньше 32 байт накладных расходов.
Вспомогательные сообщения¶
Вспомогательные данные отправляются и принимаются с помощью sendmsg(2) и recvmsg(2). В силу исторических причин перечисленные типы вспомогательных сообщений относятся к типу SOL_SOCKET, даже если они относятся к AF_UNIX. Для того, чтобы отправить их, установите значение поля cmsg_level структуры cmsghdr равным SOL_SOCKET, а в значении поля cmsg_type укажите его тип. Дополнительная информация приведена в cmsg(3).
- SCM_RIGHTS
- Передать или принять набор открытых файловых дескрипторов из другого процесса. Часть с данными содержит целочисленный массив файловых дескрипторов. Переданные файловые дескрипторы действуют так, как если бы они были созданы dup(2).
- SCM_CREDENTIALS
- Передать
или
принять
информацию
о UNIX. Может
быть
использовано
для
аутентификации.
Информация
передаётся
в виде
структуры
struct ucred
вспомогательного
сообщения.
Эта
структура
определена
в <sys/socket.h>
следующим
образом:
struct ucred {
pid_t pid; /* идентификатор посылающего процеса */
uid_t uid; /* идентификатор пользователя посылающего процесса */
gid_t gid; /* идентификатор группы посылающего процесса */ };
Начиная с glibc 2.8, чтобы получить определение данной структуры должен быть определён макрос тестирования свойств _GNU_SOURCE (до включения каких-либо заголовочных файлов).
Информация (credentials), указываемая отправителем, проверяется ядром. Процесс с идентификатором эффективного пользователя 0 может указывать значения, отличные от его собственных. Отправитель должен указать идентификатор своего процесса (если только он не имеет мандата CAP_SYS_ADMIN), свой идентификатор пользователя, эффективный идентификатор или сохранённый set-user-ID (если только он не имеет CAP_SETUID) и идентификатор своей группы, эффективный идентификатор группы или сохранённый set-group-ID (если только он не имеет CAP_SETGID). Для получения сообщения со структурой struct ucred для сокета нужно включить параметр SO_PASSCRED.
Вызовы ioctl¶
Следующие вызовы ioctl(2) возвращают информацию в аргументе value. Корректный синтаксис:
int value; error = ioctl(unix_socket, ioctl_type, &value);
Значением ioctl_type может быть:
- SIOCINQ
- Возвращает количество непрочитанных данных в очереди в приёмном буфере. Сокет не должен быть в состоянии LISTEN, иначе возвращается ошибка (EINVAL). Значение SIOCINQ определено в <linux/sockios.h>. В качестве альтернативы вы можете использовать синоним FIONREAD, определённый в <sys/ioctl.h>.
ОШИБКИ¶
- EADDRINUSE
- Заданный локальный адрес уже используется, или сокетный объект файловой системы уже существует.
- ECONNREFUSED
- Удалённый адрес, указанный connect(2) не является слушающим сокетом. Эта ошибка также может возникнуть, если имя файла назначения не является сокетом.
- ECONNRESET
- Удалённый сокет был неожиданно закрыт.
- EFAULT
- Некорректный адрес пользовательской памяти.
- EINVAL
- Передан неправильный аргумент. Основная причина — не задано значение AF_UNIX в поле sun_type передаваемых адресов или сокет находится в некорректном состоянии для производимой операции.
- EISCONN
- Вызов connect(2) запущен для уже соединённого сокета, или адрес назначения указывает на соединённый сокет.
- ENOENT
- Путь, указанный в удалённом адресе для connect(2), не существует.
- ENOMEM
- Не хватает памяти.
- ENOTCONN
- Для операции над сокетом требуется адрес назначения, а сокет не соединён.
- EOPNOTSUPP
- Вызвана потоковая операция для непотокового сокета, или произведена попытка использования параметра для внеполосных данных.
- EPERM
- Отправитель указал неправильную информацию (credentials) в структуре struct ucred.
- EPIPE
- Удалённый сокет был закрыт в потоковом сокете. Если разрешено, также будет послан сигнал SIGPIPE. Этого можно избежать, передав флаг MSG_NOSIGNAL при вызове sendmsg(2) или recvmsg(2).
- EPROTONOSUPPORT
- Указанный протокол не является AF_UNIX.
- EPROTOTYPE
- Удалённый сокет не совпадает с типом локального сокета (SOCK_DGRAM против SOCK_STREAM).
- ESOCKTNOSUPPORT
- Неизвестный тип сокета.
При создании сокетного объекта на уровне сокетов или файловой системы могут генерироваться другие ошибки. За дополнительной информацией обращайтесь к соответствующей справочной странице.
ВЕРСИИ¶
SCM_CREDENTIALS и абстрактное пространство имён появились в Linux 2.2 и не должны использоваться в переносимых программах. Некоторые клоны BSD также поддерживают передачу дополнительной информации (credential), но методы реализации передачи могут серьезно отличаться на разных системах.
ЗАМЕЧАНИЯ¶
В реализации Linux учитываются права доступа к каталогу, в котором находятся сокеты, видимые в файловой системе. Владелец, группа и права, присвоенные сокетам, могут быть изменены. Если процесс не имеет прав на запись и поиск (запуск) в каталоге, то создать новый сокет в нём не удастся. Соединение сокетных объектов требует права на запись/чтение. Это действие отличается от действий большинства клонов BSD, игнорирующих права доменных сокетов UNIX. Переносимые программы не должны полагаться на эту возможность для обеспечения безопасности.
Привязка сокета к имени файла создаёт сокет в файловой системе, который должен быть удалён создателем, когда необходимость в нём отпадёт (с помощью unlink(2)). Обычная система ссылок UNIX также подходит для работы с сокетами; сокет может быть удалён в любое время, а реальное удаление из файловой системы будет произведено при закрытии последней на него ссылки.
Для передачи файловых дескрипторов или информации (credentials) через SOCK_STREAM необходимо передать/принять, по меньшей мере, один байт недополнительных данных в одном из вызовов: sendmsg(2) или recvmsg(2).
В потоковых доменных сокетах UNIX отсутствует такое понятие как внеполосные данные.
ПРИМЕР¶
См. bind(2).
Пример использования SCM_RIGHTS приведён в cmsg(3).
СМОТРИТЕ ТАКЖЕ¶
recvmsg(2), sendmsg(2), socket(2), socketpair(2), cmsg(3), capabilities(7), credentials(7), socket(7)
2012-05-10 | Linux |